#include "tftpclient.h"
#include <QUdpSocket>
#include <QNetworkDatagram>
#include <QDebug>

TFtpClient::TFtpClient(QObject *parent)
    : QObject(parent)
    , socket_(new QUdpSocket(this))
{
    connect(socket_, &QUdpSocket::readyRead,
            this, &TFtpClient::readPendingDatagrams);
    connect(socket_, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(connectError(QAbstractSocket::SocketError)));
}

void TFtpClient::setHostPort(QString const& host, quint16 port)
{
    host_ = host;
    port_ = port;
}

void TFtpClient::getFile(QString const& localFileName, QString const& remoteFileName)
{
    isPut_ = false;
    localFileName_ = localFileName;
    remoteFileName_ = remoteFileName;
    fileOperateRequest(isPut_);
}

void TFtpClient::putFile(QString const& localFileName, QString const& remoteFileName)
{
    isPut_ = true;
    localFileName_ = localFileName;
    remoteFileName_ = remoteFileName;
    fileOperateRequest(isPut_);
}

void TFtpClient::stopFileTransfer()
{
    socket_->disconnectFromHost();
}

void TFtpClient::fileOperateRequest(bool isPut)
{
    tftpFile_ = TFtpClientFile::Ptr(new TFtpClientFile(socket_));
    tftpFile_->setPeerInfo(QHostAddress(host_), port_);
    bool isOK = true;
    if(isPut)
        isOK = tftpFile_->putFile(localFileName_.toStdString(),
                                  remoteFileName_.toStdString(), TFtp::BINARY);
    else
        isOK = tftpFile_->getFile(localFileName_.toStdString(),
                                  remoteFileName_.toStdString(), TFtp::BINARY);
    if(!isOK) {
        emit error("Local File not Found");
    } else {
        emit started();
    }
}

void TFtpClient::connectError(QAbstractSocket::SocketError)
{
    emit error("Connect host is failed");
}

void TFtpClient::readPendingDatagrams()
{
    while (socket_->hasPendingDatagrams()) {
        QByteArray datagram;
        QHostAddress peer_addr;
        quint16 peer_port;
        datagram.resize(static_cast<int>(socket_->pendingDatagramSize()));
        socket_->readDatagram(datagram.data(), datagram.size(), &peer_addr, &peer_port);
        if(tftpFile_) {
            tftpFile_->setPeerInfo(peer_addr, peer_port);
            tftpFile_->process((uint8_t *)datagram.data(), datagram.size());
            emit progress(tftpFile_->file_bytes(), tftpFile_->filesize());
            if(tftpFile_->is_finished()) {
                if(tftpFile_->is_error()) {
                    emit error(QString::fromStdString(tftpFile_->error_msg()));
                } else {
                    emit finished();
                }
            }
        }
    }
}
